/* * Hibernate, Relational Persistence for Idiomatic Java * * JBoss, Home of Professional Open Source * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.hibernate.hql.lucene.internal.builder; import java.util.EnumSet; import java.util.List; import org.apache.lucene.document.Field; import org.apache.lucene.document.Field.Index; import org.hibernate.hql.ast.spi.EntityNamesResolver; import org.hibernate.hql.lucene.internal.logging.Log; import org.hibernate.hql.lucene.internal.logging.LoggerFactory; import org.hibernate.hql.lucene.spi.FieldBridgeProvider; import org.hibernate.search.bridge.FieldBridge; import org.hibernate.search.engine.metadata.impl.DocumentFieldMetadata; import org.hibernate.search.engine.metadata.impl.EmbeddedTypeMetadata; import org.hibernate.search.engine.metadata.impl.PropertyMetadata; import org.hibernate.search.engine.metadata.impl.TypeMetadata; import org.hibernate.search.engine.spi.EntityIndexBinding; import org.hibernate.search.metadata.NumericFieldSettingsDescriptor.NumericEncodingType; import org.hibernate.search.spi.SearchIntegrator; /** * Provides functionality for dealing with Lucene-mapped properties of indexed Java types. * * @author Gunnar Morling */ public class ClassBasedLucenePropertyHelper extends LucenePropertyHelper { private static final Log log = LoggerFactory.make(); private final SearchIntegrator searchFactory; private final EntityNamesResolver entityNames; private final FieldBridgeProvider fieldBridgeProvider; public ClassBasedLucenePropertyHelper(SearchIntegrator searchFactory, EntityNamesResolver entityNames) { this( searchFactory, entityNames, null ); } public ClassBasedLucenePropertyHelper(SearchIntegrator searchFactory, EntityNamesResolver entityNames, FieldBridgeProvider fieldBridgeProvider) { this.searchFactory = searchFactory; this.entityNames = entityNames; this.fieldBridgeProvider = fieldBridgeProvider; } @Override public FieldBridge getFieldBridge(String entityType, List<String> propertyPath) { if ( fieldBridgeProvider != null ) { return fieldBridgeProvider.getFieldBridge( entityType, fieldName( propertyPath ) ); } Class<?> type = getType( entityType ); String[] propertyPathAsArray = propertyPath.toArray( new String[propertyPath.size()] ); EntityIndexBinding entityIndexBinding = getIndexBinding( searchFactory, type ); if ( isIdentifierProperty( entityIndexBinding, propertyPathAsArray ) ) { return entityIndexBinding.getDocumentBuilder().getIdBridge(); } PropertyMetadata metadata = getLeafTypeMetadata( type, propertyPathAsArray ).getPropertyMetadataForProperty( propertyPathAsArray[propertyPathAsArray.length - 1] ); if ( metadata == null ) { // not a leaf return null; } // TODO Consider properties with several fields return metadata.getFieldMetadataSet().iterator().next().getFieldBridge(); } @Override public NumericEncodingType getNumericEncodingType(String entityType, List<String> propertyPath) { Class<?> type = getType( entityType ); TypeMetadata typeMetadata = getLeafTypeMetadata( type, propertyPath.toArray( new String[propertyPath.size()] ) ); DocumentFieldMetadata fieldMetadata = typeMetadata.getDocumentFieldMetadataFor( fieldName( propertyPath ) ); if ( fieldMetadata != null ) { return fieldMetadata.getNumericEncodingType(); } return null; } private Class<?> getType(String typeName) { Class<?> type = entityNames.getClassFromName( typeName ); if ( type == null ) { throw new IllegalStateException( "Unknown entity name " + typeName ); } return type; } public boolean exists(Class<?> type, List<String> propertyPath) { return exists( type, propertyPath.toArray( new String[propertyPath.size()] ) ); } public boolean exists(Class<?> type, String... propertyPath) { EntityIndexBinding entityIndexBinding = getIndexBinding( type ); if ( isIdentifierProperty( entityIndexBinding, propertyPath ) ) { return true; } TypeMetadata metadata = entityIndexBinding.getDocumentBuilder().getMetadata(); for ( int i = 0; i < propertyPath.length - 1; i++ ) { Iterable<EmbeddedTypeMetadata> embeddedTypeMetadata = metadata.getEmbeddedTypeMetadata(); metadata = getEmbeddedTypeMetadata( embeddedTypeMetadata, propertyPath[i] ); if ( metadata == null ) { return false; } } PropertyMetadata propertyMetadataForProperty = metadata.getPropertyMetadataForProperty( propertyPath[propertyPath.length - 1] ); boolean b = getEmbeddedTypeMetadata( metadata.getEmbeddedTypeMetadata(), propertyPath[propertyPath.length - 1] ) != null; return propertyMetadataForProperty != null || b; } private TypeMetadata getLeafTypeMetadata(Class<?> type, String... propertyPath) { EntityIndexBinding entityIndexBinding = getIndexBinding( searchFactory, type ); TypeMetadata leafTypeMetadata = entityIndexBinding.getDocumentBuilder().getMetadata(); for ( int i = 0; i < propertyPath.length; i++ ) { Iterable<EmbeddedTypeMetadata> embeddedTypeMetadata = leafTypeMetadata.getEmbeddedTypeMetadata(); TypeMetadata metadata = getEmbeddedTypeMetadata( embeddedTypeMetadata, propertyPath[i] ); if ( metadata != null ) { leafTypeMetadata = metadata; } } return leafTypeMetadata; } private EmbeddedTypeMetadata getEmbeddedTypeMetadata(Iterable<EmbeddedTypeMetadata> embeddedTypeMetadata, String name) { for ( EmbeddedTypeMetadata metadata : embeddedTypeMetadata ) { if ( metadata.getEmbeddedPropertyName().equals( name ) ) { return metadata; } } return null; } public boolean isAnalyzed(Class<?> type, List<String> propertyPath) { return isAnalyzed( type, propertyPath.toArray( new String[propertyPath.size()] ) ); } public boolean isAnalyzed(Class<?> type, String... propertyPath) { EntityIndexBinding entityIndexBinding = getIndexBinding( type ); if ( isIdentifierProperty( entityIndexBinding, propertyPath ) ) { return false; } TypeMetadata metadata = getLeafTypeMetadata( type, propertyPath ); Index index = metadata.getPropertyMetadataForProperty( propertyPath[propertyPath.length - 1] ).getFieldMetadata().iterator().next().getIndex(); return EnumSet.of( Field.Index.ANALYZED, Field.Index.ANALYZED_NO_NORMS ).contains( index ); } public boolean isEmbedded(Class<?> type, List<String> propertyPath) { return isEmbedded( type, propertyPath.toArray( new String[propertyPath.size()] ) ); } /** * Determines whether the given property path denotes an embedded entity (not a property of such entity). * * @param type the indexed type * @param propertyPath the path of interest * @return {@code true} if the given path denotes an embedded entity of the given indexed type, {@code false} * otherwise. */ public boolean isEmbedded(Class<?> type, String... propertyPath) { if ( propertyPath.length == 0 ) { return false; } EntityIndexBinding entityIndexBinding = getIndexBinding( type ); TypeMetadata metadata = entityIndexBinding.getDocumentBuilder().getMetadata(); for ( int i = 0; i < propertyPath.length; i++ ) { Iterable<EmbeddedTypeMetadata> embeddedTypeMetadata = metadata.getEmbeddedTypeMetadata(); metadata = getEmbeddedTypeMetadata( embeddedTypeMetadata, propertyPath[i] ); if ( metadata == null ) { break; } } return metadata != null; } private boolean isIdentifierProperty(EntityIndexBinding entityIndexBinding, String... propertyPath) { return propertyPath.length == 1 && propertyPath[0].equals( entityIndexBinding.getDocumentBuilder().getIdPropertyName() ); } private EntityIndexBinding getIndexBinding(Class<?> type) { return getIndexBinding( searchFactory, type ); } private EntityIndexBinding getIndexBinding(SearchIntegrator searchFactory, Class<?> type) { EntityIndexBinding entityIndexBinding = searchFactory.getIndexBinding( type ); if ( entityIndexBinding == null ) { throw log.getNoIndexedEntityException( type.getCanonicalName() ); } return entityIndexBinding; } }